#ifndef __WORLD_HH__
#define __WORLD_HH__

#include <mc/types.h>
#include <util/singleton.h>
#include <util/tools.h>
#include <mc/block.h>
#include <mc/chunk.h>
#include <mc/crosshair.h>
#include <mc/sky.h>
#include <vector>
#include <iostream>
#include <set>
#include <map>

namespace mc
{

#define WORLD_WIDTH 128
#define WORLD_LENGTH 128
#define WORLD_HEIGHT 128

class World
{
    friend class util::Singleton<World>;
    friend class Loader;

private:
    //! @brief 私有构造
    World();
    ~World() noexcept;

public:
    //! @brief 获取坐标 [x, y, z] 处的方块类型
    const BlockType& block(float x, float y, float z) const
    { return this->block(util::ROUND(x), util::ROUND(y), util::ROUND(z)); }
    BlockType& block(float x, float y, float z) 
    { 
        return const_cast<BlockType&>(const_cast<const World*>(this)->block(x, y, z)); 
    }

    //! @brief 获取坐标 [x, y, z] 处的方块类型
    const BlockType& block(int64_t x, int64_t y, int64_t z) const;
    BlockType& block(int64_t x, int64_t y, int64_t z)
    {
        return const_cast<BlockType&>(const_cast<const World*>(this)->block(x, y, z)); 
    }

    //! @brief 在坐标 [x, y, z] 处放置方块
    void placeBlock(int64_t x, int64_t y, int64_t z, BlockType block, bool update = true);

    //! @brief 在坐标 pos 处放置方块
    //! @brief 调用者保证传入的坐标是取整后的
    void placeBlock(const glm::vec3& pos, BlockType block, bool update = true)
    { this->placeBlock(pos.x, pos.y, pos.z, block, update); }

    //! @brief 移除坐标 [x, y, z] 处的方块，并且返回原方块类型
    BlockType removeBlock(int64_t x, int64_t y, int64_t z, bool update = true);

    //! @brief 移除坐标 pos 处的方块，并且返回原方块类型
    //! @brief 调用者保证传入的坐标是取整后的
    BlockType removeBlock(const glm::vec3& pos, bool update = true)
    { return this->removeBlock(pos.x, pos.y, pos.z, update); }

    //! @brief 判断指定坐标是否为 EMPTY
    bool isEmptyBlock(float x, float y, float z) const
    { 
        return this->block(x, y, z) == BlockType::EMPTY; 
    }
    bool isEmptyBlock(const glm::vec3& pos) const 
    {
        return this->block(pos.x, pos.y, pos.z) == BlockType::EMPTY;
    }

    //! @brief 绘制世界
    void draw(const glm::mat4& view);

    //! @brief 初始化世界资源
    void initial(const glm::mat4& projection);

    //! @brief 更新区块
    void updateChunks(const ChunkID& oldChunkId, const ChunkID& newChunkId);

    //! @brief 释放资源
    void release();

private:
    //! @brief 种子 
    uint64_t _seed;
    //! @brief 加载半径
    unsigned int _radius;
    
    //! @brief 区块
    std::map<ChunkID, ChunkMsg> _chunkMap;
    std::set<Chunk*> _chunks;
    unsigned int _chunkRadius;

    //! @brief 天空对象
    Sky* _sky;
    //! @brief 准心
    Crosshair* _crosshair;
};
}

#endif